﻿using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
namespace DX
{
    public static class ServiceExtensions
    {

        public static void ReplaceService<TService, TImplService>(this IServiceCollection services)
        {
            var type = typeof(TService);
            var item = services.FirstOrDefault(x => x.ServiceType == type);
            if (item == null) throw new ServiceTypeNotFoundException($"{type.FullName} not exist in ServiceCollection");
            services.Add(new ServiceDescriptor(type, typeof(TImplService), item.Lifetime));
            services.Remove(item);
        }
        public static void ReplaceService<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory)
        {
            var type = typeof(TService);
            var item = services.FirstOrDefault(x => x.ServiceType == type);
            if (item == null) throw new ServiceTypeNotFoundException($"{type.FullName} not exist in ServiceCollection");
            services.Add(new ServiceDescriptor(type, implementationFactory, item.Lifetime));
            services.Remove(item);
        }
        public static void ReplaceService<TService>(this IServiceCollection services, TService instance)
        {
            var type = typeof(TService);
            var item = services.FirstOrDefault(x => x.ServiceType == type);
            if (item == null) throw new ServiceTypeNotFoundException($"{type.FullName} not exist in ServiceCollection");
            services.Add(new ServiceDescriptor(type, instance));
            services.Remove(item);
        }
        public static T GetInstance<T>(this IServiceCollection services)
        {

            var obj = services.GetInstance(typeof(T));
            return obj is T t ? t : default;
        }
        public static object GetInstance(this IServiceCollection services, Type type)
        {
            var item = services.FirstOrDefault(x => x.ServiceType == type);
            if (item == null)
            {
                return null;
            }
            if (item.ImplementationInstance != null) return item.ImplementationInstance;
            if (item.ImplementationFactory != null)
            {
                return item.ImplementationFactory(null);
            }
            if (item.ImplementationType != null)
            {
                var constructor = item.ImplementationType.GetConstructors().FirstOrDefault();
                var constructorArgs = constructor.GetParameters();
                object[] args = constructorArgs.Select(n => services.GetInstance(n.ParameterType)).ToArray();
                return constructor.Invoke(args);
            }
            return null;
        }

        public static void AddJson(this IServiceCollection services)
        {
            services.AddSingleton<ICacheProvider, CacheProvider>();
            services.PostConfigure<JsonSerializerSettings>(opt =>
            {
             
            });
            services.AddSingleton<JsonSerializeProvider>();
            services.AddSingleton<ISerializeProvider>(n=>n.GetService<JsonSerializeProvider>());
            services.AddSingleton<IBufferSerializeProvider>(n => n.GetService<JsonSerializeProvider>());
        }
    }

    public class ServiceTypeNotFoundException : DXException
    {

        public ServiceTypeNotFoundException(string message) : base(message) { }
        public ServiceTypeNotFoundException(string message, Exception inner) : base(message, inner) { }

    }
}